
#include "IdealObserver.h"

int main(int argc, const char* argv[])
{
	int nRetCode = 0;
	char strTemp[10001];
	strTemp[0] = 0;

	CMyRandom::InitRandomSeed();
	CImageEx::Initialize();

	if (1)
	{
		string strFN_Configuration		=	argv[1];
		string strOperation				=	((argc>2&&argv[2]) ? string(argv[2]) : "") + "000000";

		int Op_Debug					=	0; //CDataStructureTools::Hex2Num(strOperation[0]);
		int Op_Show_E_dD_dR				=	CDataStructureTools::Hex2Num(strOperation[0]);
		int Op_Show_T_D_F_R				=	15; //CDataStructureTools::Hex2Num(strOperation[2]);
		int Op_RandomSample_T_D_F_R		=	CDataStructureTools::Hex2Num(strOperation[1]);
		int Op_SaveObservationSet		=	3;
		int Op_Op_ObservationSet		=	CDataStructureTools::Hex2Num(strOperation[2]);

		bool Op_ObservationSet_Clear	=	(Op_Op_ObservationSet == 1);
		bool Op_ObservationSet_Push_R	=	(Op_Op_ObservationSet == 2);
		bool Op_ObservationSet_Calc_F	=	(Op_Op_ObservationSet == 3);
		bool Op_ObservationSet_Simulate	=	(Op_Op_ObservationSet == 4);

		CConfiguration Config(strFN_Configuration);
		Config.Load();
		string strFN_OutLog									=	Config.GetString("strFN_OutLog", "xxx.log");

		GIMS.IW												=	Config.GetInt("IW");
		GIMS.IH												=	Config.GetInt("IH");
		GIMS.CW												=	Config.GetInt("CW");
		GIMS.CH												=	Config.GetInt("CH");

		GIMS.Output_CW										=	Config.GetInt("Output_CW");
		GIMS.Output_CH										=	Config.GetInt("Output_CH");

		GIMS.K1												=	Config.GetDouble("K1");
		GIMS.K2												=	Config.GetDouble("K2");
		GIMS.K3												=	Config.GetDouble("K3", 1.0);
		GIMS.Sigma											=	Config.GetDouble("Sigma");

		GIMS.strFN_ImgTemplate								=	Config.GetString("strFN_ImgTemplate");
		GIMS.strFN_EdgletConfusionMatrix					=	Config.GetString("strFN_EdgletConfusionMatrix");
		GIMS.strFN_EdgletPriorDistribution					=	Config.GetString("strFN_EdgletPriorDistribution");

		GIMS.strFN_Set_T									=	Config.GetString("strFN_Set_T");
		GIMS.strFN_Set_F									=	Config.GetString("strFN_Set_F");

		GIMS.FixationStrideFactor							=	Config.GetDouble("FixationStrideFactor", 0.0);
		
		GIMS.strFN_ListObservation_Text_Input				=	Config.GetString("strFN_ListObservation_Text_Input");
		GIMS.strPN_BaseObservation_Text_Input				=	Config.GetString("strPN_BaseObservation_Text_Input");
		GIMS.strPN_BaseObservation_Show_Input				=	Config.GetString("strPN_BaseObservation_Show_Input");
		GIMS.InputObservationGeneration_Amount_F			=	Config.GetInt("InputObservationGeneration_Amount_F");
		GIMS.InputObservationGeneration_Amount_O_per_F		=	Config.GetInt("InputObservationGeneration_Amount_R_per_F");

		CImageModelInstance::CAnalysisParameter AnalysisParameter;
		AnalysisParameter.Sampling_IterationAmount			=	Config.GetInt("Amount_Sampling", 131072);
		AnalysisParameter.SeedAmount_Exponent				=	Config.GetDouble("AP.SeedAmount_Exponent", 0.5);
		AnalysisParameter.SeedAmount_Coefficient			=	Config.GetDouble("AP.SeedAmount_Coefficient", 1.0);
		AnalysisParameter.T_AbandonThreshold				=	Config.GetDouble("AP.T_AbandonThreshold", 0.001);
		AnalysisParameter.Ra_AffectThreshold				=	Config.GetDouble("AP.Ra_AffectThreshold", 0.001);
		AnalysisParameter.Cell_IndependentThreshold			=	Config.GetDouble("AP.Cell_IndependentThreshold", 0.001);

		GIMS.strPN_Prediction_Output						=	Config.GetString("strPN_Prediction_Output");

		GIMS.strFN_Show_EdgletCode							=	Config.GetString("strFN_Show_EdgletCode");
		GIMS.strFN_Show_Distribution_D_given_T				=	Config.GetString("strFN_Show_Distribution_D_given_T");
		GIMS.strFN_Show_Distribution_R_given_D_F			=	Config.GetString("strFN_Show_Distribution_R_given_D_F");
		GIMS.strFN_IMI_T_Text								=	Config.GetString("strFN_IMI_T_Text");
		GIMS.strFN_IMI_T_Show								=	Config.GetString("strFN_IMI_T_Show");
		GIMS.strFN_IMI_D_Text								=	Config.GetString("strFN_IMI_D_Text");
		GIMS.strFN_IMI_D_Show								=	Config.GetString("strFN_IMI_D_Show");
		GIMS.strFN_IMI_F									=	Config.GetString("strFN_IMI_F");
		GIMS.strFN_IMI_R_Text								=	Config.GetString("strFN_IMI_R_Text");
		GIMS.strFN_IMI_R_Show								=	Config.GetString("strFN_IMI_R_Show");

		GIMS.strFN_ObservationSet_List						=	Config.GetString("strFN_ObservationSet_List");
		GIMS.strPN_ObservationSet_Text						=	Config.GetString("strPN_ObservationSet_Text");
		GIMS.strPN_ObservationSet_Show						=	Config.GetString("strPN_ObservationSet_Show");

		GIMS.strFN_SimulationLog							=	Config.GetString("strFN_SimulationLog", "Simulation.log");

		cout<<endl;
		ofstream oLog(strFN_OutLog.c_str());

		// Main Code
		if (1)
		{

			CImageModelInstance IMI;
			CImg<int> imgOutput;

			IMI.InitObjectTemplate(GIMS.strFN_ImgTemplate, GIMS.IW, GIMS.IH, GIMS.CW, GIMS.CH);
			IMI.InitModelParameters(GIMS.K1, GIMS.K2, GIMS.K3, GIMS.Sigma);

			sprintf_s(strTemp, "K1 = %.4lf; K2 = %.4lf; K3 = %.4lf; Sigma = %.4lf",
				GIMS.K1, GIMS.K2, GIMS.K3, GIMS.Sigma);
			CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
			CExternalTools::ConsoleTools::OutputTextToStream(oLog, strTemp, true);

			IMI.LoadEdgletConfusionMatrix(GIMS.strFN_EdgletConfusionMatrix);
			IMI.LoadEdgletPriorDistribution(GIMS.strFN_EdgletPriorDistribution);

			IMI.AnalysisParameter = AnalysisParameter;

			CTransformationSet SetT;
			if (!(SetT.InputFromFile(GIMS.strFN_Set_T)))
				IMI.InitDefaultTransformationSet(SetT);
			CFixationSet SetF;
			if (!(SetF.InputFromFile(GIMS.strFN_Set_F)))
			{
				int rF = IMI.InitDefaultFixationSet(SetF, GIMS.FixationStrideFactor);
				sprintf_s(strTemp, "Made {F}, Fixation Radius = %d", rF);
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(oLog, strTemp, true);
			}

			int IMI_T_Index;
			int IMI_F_Index;
			CTransformation IMI_Transformation;
			CFixation IMI_Fixation;
			CSimpleTypeArray<int> obsvD;
			CSimpleTypeArray<int> obsvR;

			CObservationSet ObservationSet;
			ObservationSet.Clear();

			int H_Extent = 20;

			if (1)
			{
				// Load T
				{
					string strFN_TargetText = GIMS.strFN_IMI_T_Text;

					ifstream inFile(strFN_TargetText.c_str());
					inFile>>IMI_T_Index;
					IMI_Transformation.InputFromStream(inFile);
					IMI.SetTransformation(IMI_Transformation);
					inFile.close();
					inFile.clear();

					for ( IMI_T_Index = SetT.Size-1; IMI_T_Index >= 0; --IMI_T_Index )
					{
						if (IMI_Transformation.base_x==SetT.List.pElement[IMI_T_Index].base_x &&
							IMI_Transformation.base_y==SetT.List.pElement[IMI_T_Index].base_y)
							break;
					}
				}

				// Load D
				{
					string strFN_TargetText = GIMS.strFN_IMI_D_Text;

					CObservation oD;
					IMI.InputObservationFromText(oD, strFN_TargetText);
					obsvD = oD.Result;
				}

				// Load F
				{
					string strFN_TargetText = GIMS.strFN_IMI_F;

					ifstream inFile(strFN_TargetText.c_str());
					inFile>>IMI_F_Index;
					IMI_Fixation.InputFromStream(inFile);
					IMI.SetFixation(IMI_Fixation);
					inFile.close();
					inFile.clear();
				}

				// Load R
				{
					string strFN_TargetText = GIMS.strFN_IMI_R_Text;

					CObservation RF;
					IMI.InputObservationFromText(RF, strFN_TargetText);
					obsvR = RF.Result;
				}
			}
			if (1)
			{
				// Load Observation Set
				ObservationSet.InputList(
					GIMS.strFN_ObservationSet_List,
					GIMS.strPN_ObservationSet_Text,
					IMI);
				sprintf_s(strTemp, "Current |Observation| = %d;", ObservationSet.Size);
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			}

			if (Op_Show_E_dD_dR & 1)
			{
				// Show Edglet Code
				string strFN_TargetImage = GIMS.strFN_Show_EdgletCode;
				CImg<int> imgOutput;

				CImg<int> imgTempInt;
				imgTempInt.assign(IMI.IE * GIMS.Output_CW, GIMS.Output_CH, 1, 1);
				int i;
				CRectBox<int> iBox;
				CEdglet te;
				for ( i = 0; i < IMI.IE; ++i )
				{
					te.myInit(i);
					iBox.x = i * GIMS.Output_CW; iBox.y = 0; iBox.w = GIMS.Output_CW; iBox.h = GIMS.Output_CH;
					te.ToImage(imgTempInt.data, (int)imgTempInt.width, (int)imgTempInt.height, iBox);
				}
				DrawGridImage(imgOutput, imgTempInt, IMI.IE, 1, GIMS.Output_CW, GIMS.Output_CH, 0);

				CExternalTools::mySaveImage(strFN_TargetImage, imgOutput);
			} // (Op_Show_E_dD_dR & 1)

			if (Op_RandomSample_T_D_F_R & 1)
			{
				// Random Sample T

				IMI_T_Index = CMyRandom::DiscreteSample(SetT.Weights.pElement, SetT.Size);
				IMI_Transformation = SetT.List.pElement[IMI_T_Index];
				IMI.SetTransformation(IMI_Transformation);

				sprintf_s(strTemp, "Randomly Sampled T;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_RandomSample_T_D_F_R & 1)

			if (Op_Show_T_D_F_R & 1)
			{
				// Show T

				double p = 0.0;
				if (IMI_T_Index>=0 && IMI_T_Index<SetT.Size) p = SetT.Weights.pElement[IMI_T_Index];
				sprintf_s(strTemp, "[T] (%d/%d) = <%+04d,%+04d>, P = %.4lf%%;",
					IMI_T_Index, SetT.Size,
					IMI_Transformation.base_x,
					IMI_Transformation.base_y,
					p * 100.0);
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;

				CImg<int> imgOutput;
				IMI.SetTransformation(IMI_Transformation);
				IMI.Ouptut_PrototypeD_ToImage(imgOutput, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);
				CExternalTools::OutputTextToImage(imgOutput, strTemp, 4, imgOutput.height - H_Extent + 2, 0, 0, 0, 255, 255, 255, 12);
				CExternalTools::mySaveImage(GIMS.strFN_IMI_T_Show, imgOutput);

			} // (Op_Show_T_D_F_R & 1)

			if (Op_Show_E_dD_dR & 2)
			{
				// Show Distribution D on T
				string strFN_TargetImage = GIMS.strFN_Show_Distribution_D_given_T;
				CImg<int> imgOutput;

				CDistribution dtrbD;
				IMI.SetTransformation(IMI_Transformation);
				IMI.Predict_D_given_T(dtrbD);
				dtrbD.OutputToImage(imgOutput, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);
				sprintf_s(strTemp, "T = <%+04d,%+04d>;", IMI_Transformation.base_x, IMI_Transformation.base_y);
				CExternalTools::OutputTextToImage(imgOutput, strTemp, 4, imgOutput.height - H_Extent + 2, 0, 0, 0, 255, 255, 255, 12);
				CExternalTools::mySaveImage(strFN_TargetImage, imgOutput);
				sprintf_s(strTemp, "[Distribution_D on T] Drawn;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_Show_E_dD_dR & 2)

			if (Op_RandomSample_T_D_F_R & 2)
			{
				// Random Sample D on T

				IMI.SetTransformation(IMI_Transformation);
				IMI.RandomSample_D_given_T(obsvD);

				sprintf_s(strTemp, "Randomly Sampled [D];");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_RandomSample_T_D_F_R & 2)

			if (Op_Show_T_D_F_R & 2)
			{
				// Show D
				string strFN_TargetImage = GIMS.strFN_IMI_D_Show;
				CImg<int> imgOutput;

				IMI.OutputObserveResultToImage(imgOutput, obsvD, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);
				sprintf_s(strTemp, "T = <%+04d,%+04d>;", IMI_Transformation.base_x, IMI_Transformation.base_y);
				CExternalTools::OutputTextToImage(imgOutput, strTemp, 4, imgOutput.height - H_Extent + 2, 0, 0, 0, 255, 255, 255, 12);
				CExternalTools::mySaveImage(strFN_TargetImage, imgOutput);
				sprintf_s(strTemp, "[D on T] Drawn;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_Show_T_D_F_R & 2)

			if (Op_RandomSample_T_D_F_R & 4)
			{
				// Random Sample F

				IMI_F_Index = CMyRandom::NextInt(SetF.Size);
				IMI_Fixation = SetF.List.pElement[IMI_F_Index];
				IMI.SetFixation(IMI_Fixation);

				sprintf_s(strTemp, "Randomly Sampled [F];");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_RandomSample_T_D_F_R & 4)

			if (Op_Show_T_D_F_R & 4)
			{
				// Show F

				sprintf_s(strTemp, "[F] (%d/%d) = <%03d,%03d>;",
					IMI_F_Index, SetF.Size,
					IMI_Fixation.ob_x,
					IMI_Fixation.ob_y);
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_Show_T_D_F_R & 4)

			if (Op_Show_E_dD_dR & 4)
			{
				// Show Distribution R on D F
				string strFN_TargetImage = GIMS.strFN_Show_Distribution_R_given_D_F;
				CImg<int> imgOutput;

				CDistribution dtrbR;
				IMI.SetFixation(IMI_Fixation);
				IMI.Predict_R_given_obsvD_F(dtrbR, obsvD);
				dtrbR.OutputToImage(imgOutput, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);
				sprintf_s(strTemp, "T = <%+04d,%+04d>; F = <%03d,%03d>;",
					IMI_Transformation.base_x, IMI_Transformation.base_y,
					IMI_Fixation.ob_x, IMI_Fixation.ob_y);
				CExternalTools::OutputTextToImage(imgOutput, strTemp, 4, imgOutput.height - H_Extent + 2, 0, 0, 0, 255, 255, 255, 12);

				CExternalTools::mySaveImage(strFN_TargetImage, imgOutput);
				sprintf_s(strTemp, "[Distribution_R on D F] Drawn;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_Show_E_dD_dR & 4)

			if (Op_RandomSample_T_D_F_R & 8)
			{
				// Random Sample R on D R

				CObservation RF;
				RF.Fixation = IMI_Fixation;
				IMI.SetFixation(IMI_Fixation);
				IMI.RandomSample_R_given_obsvD_F(RF, obsvD);
				obsvR = RF.Result;

				sprintf_s(strTemp, "Randomly Sampled [R on D F];");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_RandomSample_T_D_F_R & 8)

			if (Op_Show_T_D_F_R & 8)
			{
				// Show R
				string strFN_TargetImage = GIMS.strFN_IMI_R_Show;
				CImg<int> imgOutput;

				IMI.OutputObserveResultToImage(imgOutput, obsvR, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);

				CExternalTools::mySaveImage(strFN_TargetImage, imgOutput);
				sprintf_s(strTemp, "[R on D F] Drawn;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_Show_T_D_F_R & 8)

			if (Op_ObservationSet_Clear)
			{
				ObservationSet.Clear();

				sprintf_s(strTemp, "Observation Set Cleared;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<endl;
				oLog<<endl;
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_ObservationSet_Clear)

			if (Op_ObservationSet_Push_R)
			{
				CObservation RF;
				RF.Fixation = IMI_Fixation;
				RF.Result = obsvR;
				ObservationSet.NewObservation(RF);

				sprintf_s(strTemp, "Pushed New Observation, Current Set Size = %d;", ObservationSet.Size);
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<endl;
				oLog<<endl;
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_ObservationSet_Push_R)

			if (Op_ObservationSet_Calc_F)
			{
				CSimpleTypeArray<double> vT_P_T;
				double H_T;
				int Index_Best_T, Index_Best_F;
				CFixation NextF;
				CSimpleTypeArray<double> List_CH_F;

				sprintf_s(strTemp, "Start Seeking new Fixation;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<endl;
				oLog<<endl;
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;

				IMI.Analyse2_given_TT_RR_FF_F(
					vT_P_T, Index_Best_T, H_T,
					List_CH_F, Index_Best_F, NextF,
					SetT, -1,
					ObservationSet,
					SetF,
					oLog,
					GIMS.Output_CW, GIMS.Output_CH, H_Extent,
					GIMS.strPN_Prediction_Output);
			}

			if (Op_ObservationSet_Simulate)
			{
				CExternalTools::ConsoleTools::MakeDirectory(GIMS.strPN_Prediction_Output, true);

				ofstream outFile_SimulationLog(GIMS.strFN_SimulationLog.c_str());

				CSimpleTypeArray<double> List_CH;
				CSimpleTypeArray<double> List_H_T;

				ObservationSet.Clear();
				CObservation RF;
				RF.Fixation = IMI_Fixation;
				RF.Result = obsvR;
				ObservationSet.NewObservation(RF);

				List_CH.Clear();
				{
					int i;
					double o_CH_F, ttt;
					o_CH_F = 0.0;
					for ( i = 0; i < SetT.Size; ++i )
					{
						ttt =  SetT.Weights.pElement[i];
						if (ttt < MINIMUM_DOUBLE_EPS_C) continue;
						o_CH_F -= ttt * CMyMath::my_log(ttt);
					}
					List_CH.PushBack(o_CH_F);
				}
				List_H_T.Clear();

				CSimpleTypeArray<double> vT_P_T;
				double H_T;
				int Index_Best_T, Index_Best_F;
				CFixation NextF;
				CSimpleTypeArray<double> vF_CH;

				sprintf_s(strTemp, "Start Simulation;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<endl; 
				oLog<<endl;
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;

				sprintf_s(strTemp,
					"Ob_i\tF_x\tF_y\tbT_x\tbT_y\tP[bT]\tCH_bF(T|{I,F})\tH(T)\t\tlog(H(T))");
				CExternalTools::ConsoleTools::OutputTextToStream(outFile_SimulationLog, strTemp, true);

				int i_Observation;
				for ( i_Observation = 0; ; ++i_Observation )
				{
					CExternalTools::ConsoleTools::MakeCurrentLine("", true);
					oLog<<endl;
					sprintf_s(strTemp, "Start Analyse Observation %d;", i_Observation);
					CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
					oLog<<strTemp<<endl;

					const CObservation& LastRF = ObservationSet.List.pElement[i_Observation];
					sprintf_s(strTemp, "%s%02d.txt", GIMS.strPN_Prediction_Output.c_str(), i_Observation);
					IMI.OutputObservationToText(strTemp, LastRF);
					IMI.OutputObserveResultToImage(imgOutput, LastRF, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);
					sprintf_s(strTemp, "F = <%03d,%03d>;", // T = <%+04d,%+04d>;",
						LastRF.Fixation.ob_x, LastRF.Fixation.ob_y
						); // ,IMI_Transformation.base_x, IMI_Transformation.base_y);
					CExternalTools::OutputTextToImage(imgOutput, strTemp, 4, imgOutput.height - H_Extent + 2, 0, 0, 0, 255, 255, 255, 16);
					sprintf_s(strTemp, "%s%02d.jpg", GIMS.strPN_Prediction_Output.c_str(), i_Observation);
					CExternalTools::mySaveImage(strTemp, imgOutput);

					string strPN_Analysis;
					sprintf_s(strTemp, "%s%02d\\", GIMS.strPN_Prediction_Output.c_str(), i_Observation);
					strPN_Analysis = strTemp;
					IMI.Analyse2_given_TT_RR_FF_F(
						vT_P_T, Index_Best_T, H_T,
						vF_CH, Index_Best_F, NextF,
						SetT, IMI_T_Index,
						ObservationSet,
						SetF,
						oLog,
						GIMS.Output_CW, GIMS.Output_CH, H_Extent,
						strPN_Analysis);

					List_H_T.PushBack(H_T);

					sprintf_s(strTemp,
						"%d\t%03d\t%03d\t%+04d\t%+04d\t%6.4lf\t%+9.6lf\t%+9.6lf\t%.4lf",
						i_Observation,
						ObservationSet.List.pElement[i_Observation].Fixation.ob_x, ObservationSet.List.pElement[i_Observation].Fixation.ob_y,
						SetT.List.pElement[Index_Best_T].base_x, SetT.List.pElement[Index_Best_T].base_y,
						vT_P_T.pElement[Index_Best_T], List_CH.pElement[i_Observation], List_H_T.pElement[i_Observation], log(List_H_T.pElement[i_Observation]));
					CExternalTools::ConsoleTools::OutputTextToStream(outFile_SimulationLog, strTemp, true);

					//sprintf_s(strTemp,
					//	"Observation %02d: F = [%03d/%03d] <+%03d, +%03d>; Best T = [%03d/%03d] <+%03d, +%03d>, P = %6.2lf%%; CH[This F] = %+8.4lf, H[T] = %+8.4lf;",
					//	i_Observation,
					//	Index_Best_F, SetF.Size,
					//	ObservationSet.List.pElement[i_Observation].Fixation.ob_x, ObservationSet.List.pElement[i_Observation].Fixation.ob_y,
					//	Index_Best_T, SetT.Size,
					//	SetT.List.pElement[Index_Best_T].base_x, SetT.List.pElement[Index_Best_T].base_y, vT_P_T.pElement[Index_Best_T] * 100.0,						
					//	List_CH.pElement[i_Observation], List_H_T.pElement[i_Observation]);
					//CExternalTools::ConsoleTools::OutputTextToStream(outFile_SimulationLog, strTemp, true);

					//break;

					sprintf_s(strTemp, "copy \"%sD_given_T_R_F.%04d.jpg\" %sD.given.BestT.After.%02d.jpg",
						strPN_Analysis.c_str(), Index_Best_T, GIMS.strPN_Prediction_Output.c_str(), i_Observation);
					CExternalTools::ConsoleTools::RunDosCommand("", strTemp);

					if (IMI_T_Index>=0 && IMI_T_Index<SetT.Size)
					{
						sprintf_s(strTemp, "copy \"%sD_given_T_R_F.%04d.jpg\" %sD.given.CorrectT.After.%02d.jpg",
							strPN_Analysis.c_str(), IMI_T_Index, GIMS.strPN_Prediction_Output.c_str(), i_Observation);
						CExternalTools::ConsoleTools::RunDosCommand("", strTemp);
					}

					sprintf_s(strTemp, "copy \"%sT_given_R_F.jpg\" %sT.After.%02d.jpg",
						strPN_Analysis.c_str(), GIMS.strPN_Prediction_Output.c_str(), i_Observation);
					CExternalTools::ConsoleTools::RunDosCommand("", strTemp);

					if (H_T < EPS) break;

					List_CH.PushBack(vF_CH.pElement[Index_Best_F]);

					RF.Fixation = NextF;
					IMI.SetFixation(NextF);
					IMI.RandomSample_R_given_obsvD_F(RF, obsvD);
					ObservationSet.NewObservation(RF);

					sprintf_s(strTemp, "copy \"%sf_given_R_F.jpg\" %sCH.After.%02d.jpg",
						strPN_Analysis.c_str(), GIMS.strPN_Prediction_Output.c_str(), i_Observation);
					CExternalTools::ConsoleTools::RunDosCommand("", strTemp);
				}

				outFile_SimulationLog.close();
				outFile_SimulationLog.clear();
			}

			if (1)
			{
				// Save T
				{
					string strFN_TargetText = GIMS.strFN_IMI_T_Text;
					ofstream outFile(strFN_TargetText.c_str());
					outFile<<IMI_T_Index<<endl;
					IMI_Transformation.OutputToStream(outFile);
					sprintf_s(strTemp, "// Prob = %.4lf%%, L-T Corner of Object = <%d,%d>",
						SetT.Weights.pElement[IMI_T_Index] * 100.0,
						IMI_Transformation.base_x + IMI.ObjectTemplate.xLow,
						IMI_Transformation.base_y + IMI.ObjectTemplate.yLow);
					outFile<<strTemp<<endl;
					outFile.close();
					outFile.clear();
				}

				// Save D
				{
					string strFN_TargetText = GIMS.strFN_IMI_D_Text;
					CObservation oD;
					oD.Fixation.Clear();
					oD.Result = obsvD;

					IMI.OutputObservationToText(strFN_TargetText, oD);
				}

				// Save F
				{
					string strFN_TargetText = GIMS.strFN_IMI_F;

					ofstream outFile(strFN_TargetText.c_str());
					outFile<<IMI_F_Index<<endl;
					IMI_Fixation.OutputToStream(outFile);
					outFile.close();
					outFile.clear();
				}

				// Save R
				{
					string strFN_TargetText = GIMS.strFN_IMI_R_Text;

					CObservation RF;
					RF.Fixation = IMI_Fixation;
					RF.Result = obsvR;
					IMI.OutputObservationToText(strFN_TargetText, RF);
				}
			}

			if (Op_SaveObservationSet & 1)
			{
				// Save Observation Set
				ObservationSet.OutputList(GIMS.strFN_ObservationSet_List, GIMS.strPN_ObservationSet_Text, IMI);
				sprintf_s(strTemp, "Saved Observation Set;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_SaveObservationSet & 1)

			if (Op_SaveObservationSet & 2)
			{
				CExternalTools::ConsoleTools::MakeDirectory(GIMS.strPN_ObservationSet_Show, true);

				CImg<int> imgOutput;
				int i_O;

				for ( i_O = 0; i_O < ObservationSet.Size; ++i_O )
				{
					const CObservation& oo = ObservationSet.List.pElement[i_O];

					IMI.OutputObserveResultToImage(imgOutput, oo.Result, GIMS.Output_CW, GIMS.Output_CH, H_Extent, true);
					sprintf_s(strTemp, "F = <%03d,%03d>;", // T = <%+04d,%+04d>;",
						oo.Fixation.ob_x, oo.Fixation.ob_y
						); // ,IMI_Transformation.base_x, IMI_Transformation.base_y);
					CExternalTools::OutputTextToImage(imgOutput, strTemp, 4, imgOutput.height - H_Extent + 2, 0, 0, 0, 255, 255, 255, 16);
					sprintf_s(strTemp, "%s%04d.jpg", GIMS.strPN_ObservationSet_Show.c_str(), i_O);
					CExternalTools::mySaveImage(strTemp, imgOutput);

					sprintf_s(strTemp, "Drawn Observation <I,F> [%d/%d];",
						i_O, ObservationSet.Size);
					CExternalTools::ConsoleTools::ClearCurrentLine();
					cout<<strTemp;
				}

				sprintf_s(strTemp, "Drawn Observation Set;");
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp<<endl;
				oLog<<strTemp<<endl;
			} // (Op_SaveObservationSet)

		} // Main Code

		cout<<endl;
		oLog.close();
		oLog.clear();

	} // Main Frame

	CImageEx::Release();
	return nRetCode;
}

